Perspectief 1, sociaal vangnet

Perspectief 1, sociaal vangnet#

import pandas as pd
import numpy as np
from scipy.stats import pearsonr
import plotly.graph_objects as go
import plotly.io as pio
pio.renderers.default = "notebook"  # Of "iframe" als "notebook" niet werkt


# ───── 1. Data inlezen ──────────────────────────────────────
MENTAL_CSV = "DB_Final/mental_welfare_dataset.csv"
CPDS_CSV   = "DB_Final/cpds-1960-2022-update-2024-2.csv"

mental = pd.read_csv(MENTAL_CSV).rename(columns={"Unnamed: 0": "drop"}, errors="ignore")
cpds = pd.read_csv(CPDS_CSV)
cpds.columns = [c.lower() for c in cpds.columns]

# ───── 2. Harmonisatie ──────────────────────────────────────
rename = {"United States of America": "United States",
          "Czech Republic": "Czechia", "Russian Federation": "Russia"}
for d in (mental, cpds):
    d["country"] = d["country"].replace(rename)

mental.rename(columns={"life_ladder": "ladder"}, inplace=True)

# ───── 3. Variabelen ────────────────────────────────────────
social_vars_all = [s.lower() for s in [
    "sstran", "socexp_t_pmp", "socexp_c_pmp", "socexp_k_pmp",
    "oldage_pmp", "survivor_pmp", "incapben_pmp", "health_pmp",
    "family_pmp", "fallow_pmp", "mpleave_pmp", "childcare_pmp",
    "homehelp_pmp", "unemp_pmp", "almp_pmp", "training_pmp",
    "housing_pmp", "othsocx_pmp"
]]
social_vars = [v for v in social_vars_all if v in cpds.columns]

# ───── 4. Merge ─────────────────────────────────────────────
merged = mental.merge(cpds[["country", "year"] + social_vars],
                      on=["country", "year"], how="inner").dropna()

# ───── 5. Correlatie berekenen en filteren ──────────────────
r_values = []
filtered_vars = []
for s in social_vars:
    r = pearsonr(merged["ladder"], merged[s])[0]
    if r >= 0.4:  # Alleen positieve verbanden >= 0.4
        r_values.append(r)
        filtered_vars.append(s)

# ───── 6. Labels en uitleg ─────────────────────────────────
soc_lbl = {
    "sstran": "Soc. transfers %GDP",
    "socexp_t_pmp": "Total soc. exp.",
    "socexp_c_pmp": "Cash soc. exp.",
    "socexp_k_pmp": "In-kind soc. exp.",
    "oldage_pmp": "Old-age ben.",
    "survivor_pmp": "Survivor ben.",
    "incapben_pmp": "Incapacity ben.",
    "health_pmp": "Health exp.",
    "family_pmp": "Family ben.",
    "fallow_pmp": "Family allowance",
    "mpleave_pmp": "Mat./Pat. leave",
    "childcare_pmp": "Child-care ben.",
    "homehelp_pmp": "Home-help ben.",
    "unemp_pmp": "Unemployment ben.",
    "almp_pmp": "ALMP programmes",
    "training_pmp": "Training prog.",
    "housing_pmp": "Housing ben.",
    "othsocx_pmp": "Other soc. exp."
}

soc_expl = {
    "sstran": "Overheidsuitgaven aan sociale transfers als % van het BBP.",
    "socexp_t_pmp": "Totale sociale overheidsuitgaven per hoofd van de bevolking.",
    "socexp_c_pmp": "Sociale uitgaven in geld, per persoon.",
    "socexp_k_pmp": "Sociale uitgaven in natura (zoals gezondheidszorg), per persoon.",
    "oldage_pmp": "Overheidsuitgaven aan pensioenen, per persoon.",
    "survivor_pmp": "Uitgaven aan nabestaanden, per persoon.",
    "incapben_pmp": "Uitgaven aan arbeidsongeschiktheid, per persoon.",
    "health_pmp": "Overheidsuitgaven aan gezondheidszorg, per persoon.",
    "family_pmp": "Overheidsuitgaven aan gezinsvoordelen, per persoon.",
    "fallow_pmp": "Kinderbijslag en soortgelijke voordelen, per persoon.",
    "mpleave_pmp": "Uitgaven aan ouderschapsverlof, per persoon.",
    "childcare_pmp": "Uitgaven aan kinderopvang, per persoon.",
    "homehelp_pmp": "Uitgaven aan thuishulp voor ouderen/zieken.",
    "unemp_pmp": "Uitgaven aan werkloosheidsuitkeringen, per persoon.",
    "almp_pmp": "Actief arbeidsmarktbeleid, zoals training/subsidies.",
    "training_pmp": "Training- en omscholingsprogramma's, per persoon.",
    "housing_pmp": "Uitgaven aan huisvestingssteun, per persoon.",
    "othsocx_pmp": "Overige sociale uitgaven, per persoon."
}

col_labels = [soc_lbl.get(s, s) for s in filtered_vars]

# ───── 7. Sorting toepassen ─────────────────────────────────
combined = sorted(zip(col_labels, r_values, filtered_vars), key=lambda x: x[1])
col_labels_sorted = [x[0] for x in combined]
r_values_sorted = [x[1] for x in combined]
filtered_vars_sorted = [x[2] for x in combined]

# ───── 8. Hovertekst opnieuw genereren ──────────────────────
hover_text_sorted = []
for i in range(len(r_values_sorted)):
    uitleg = soc_expl.get(filtered_vars_sorted[i], "")
    tekst = (
        f"<b>{col_labels_sorted[i]}</b><br>"
        f"{uitleg}<br><br>"
        f"Verband: {r_values_sorted[i]:.2f}<br>"
        f"Hoger → meer geluk"
    )
    hover_text_sorted.append(tekst)

# ───── 9. Heatmap tekenen ───────────────────────────────────
fig = go.Figure()

fig.add_trace(go.Heatmap(
    z=[r_values_sorted],
    x=col_labels_sorted,
    y=["Geluksscore"],
    colorscale='reds',
    zmin=0,
    zmax=1,
    text=[hover_text_sorted],
    hoverinfo="text",
    showscale=False  # Geen kleurbar
))

fig.update_layout(
    title="Sterkte van positieve verbanden tussen overheidsuitgaven en geluk",
    xaxis_title="Soort overheidsuitgave (oplopend verband)",
    xaxis_tickangle=-45,
    width=1100,
    height=300,
    font=dict(size=12),
    plot_bgcolor='white',
    margin=dict(l=100, r=100, t=100, b=120)  # Fix hier, was 'a'
)

fig.show()
import plotly.express as px
import pandas as pd

# Neem aan dat corr_df_gini al bestaat (zoals uit je eerdere code),
# met index = variabele naam en kolom 'Pearson r'

# 1. Maak een nette dataframe voor plotten met vertaalde variabelenamen
var_name_map = {
    "sstran": "Sociale transfer",
    "socexp_t_pmp": "Sociale uitgaven totaal",
    "socexp_c_pmp": "Consumentenuitgaven",
    "socexp_k_pmp": "Kapitaaluitgaven",
    "oldage_pmp": "Ouderdomsvoorzieningen",
    "survivor_pmp": "Overlevingsuitkeringen",
    "incapben_pmp": "Invaliditeitsuitkeringen",
    "health_pmp": "Gezondheidszorg",
    "family_pmp": "Gezinsbeleid",
    "fallow_pmp": "Arbeidsmarktbeleid (actief)",
    "mpleave_pmp": "Verlofregelingen",
    "childcare_pmp": "Kinderopvang",
    "homehelp_pmp": "Huiszorg",
    "unemp_pmp": "Werkloosheidsuitkeringen",
    "almp_pmp": "Arbeidsmarktbeleid (passief)",
    "training_pmp": "Opleidingen",
    "housing_pmp": "Woningondersteuning",
    "othsocx_pmp": "Overige sociale uitgaven"
}

# Filter de correlaties op abs(waarde) > 0.3
filtered_corr_df = corr_df_gini[(corr_df_gini["Pearson r"] > 0.3) | (corr_df_gini["Pearson r"] < -0.3)].copy()
filtered_corr_df["Naam"] = filtered_corr_df.index.map(var_name_map)

# Drop rijen waar de vertaling ontbreekt
filtered_corr_df = filtered_corr_df.dropna(subset=["Naam"])

# Bar chart maken
fig = px.bar(
    filtered_corr_df.sort_values("Pearson r"),
    x="Pearson r",
    y="Naam",
    orientation="h",
    color="Pearson r",
    color_continuous_scale="RdBu",
    range_color=[-1, 1],
    labels={"Pearson r": "Correlatie met inkomensongelijkheid", "Naam": "Sociaal vangnet variabele"},
    hover_data={"Pearson r": ":.2f"}
)

fig.update_layout(
    title="Correlaties sociaal vangnet × inkomensongelijkheid (> 0.3 of < -0.3)",
    xaxis_title="Pearson correlatiecoëfficiënt",
    yaxis_title="",
    coloraxis_showscale=True,
    plot_bgcolor="white",
    bargap=0.2
)

fig.show()


# --- Argumentatieve tekst voor de bar chart ---
# """
# Als we de discussie over ongelijkheid serieus nemen, moeten we stoppen met het idee dat álle sociale uitgaven automatisch leiden tot minder inkomensongelijkheid. Dat blijkt simpelweg niet uit de data.
# 
# De interactieve grafiek hiernaast laat dit glashelder zien. We hebben onderzocht welke vormen van sociale uitgaven in de praktijk daadwerkelijk samenhangen met minder ongelijkheid, gemeten via de postfiscale Gini-coëfficiënt. En wat blijkt? Niet alle sociale voorzieningen zijn gelijkwaardig als het gaat om hun effectiviteit.
# 
# We tonen hier alleen de variabelen die een duidelijke correlatie laten zien, sterker dan +0.3 of zwakker dan -0.3. Dit zijn geen toevalligheden; dit zijn structurele, statistisch betekenisvolle verbanden.
# 
# Wat direct opvalt: uitgaven aan zaken als gezinsbeleid, ouderdomsvoorzieningen en actief arbeidsmarktbeleid vertonen een negatieve correlatie met inkomensongelijkheid. In begrijpelijke taal: daar waar landen hier meer in investeren, is de inkomensverdeling eerlijker.
# 
# Maar let op — sommige uitgaven vertonen juist een positieve correlatie. Dat betekent dat in landen waar bijvoorbeeld bepaalde vormen van sociale uitgaven hoger liggen, de ongelijkheid óók hoger is. Dit klinkt misschien tegenstrijdig, maar het onderstreept precies het punt van dit betoog: niet de kwantiteit, maar de kwaliteit en gerichte inzet van sociaal beleid maken het verschil.
# 
# Kortom, als we blind blijven inzetten op 'meer sociale uitgaven' zonder kritisch te kijken naar de samenstelling en het doel van die uitgaven, missen we de kern. Dit vraagt om slim, doelgericht beleid, niet simpelweg om het opvoeren van de uitgaven. De data liegen niet — en de grafiek laat precies zien waarom nuance essentieel is als we echt werk willen maken van het verkleinen van ongelijkheid.
# """


# --- Bubble plot van top 3 sterkste correlaties ---
top3_df = filtered_corr_df.copy()
top3_df["abs_corr"] = top3_df["Pearson r"].abs()
top3_df = top3_df.sort_values("abs_corr", ascending=False).head(3)

fig2 = px.scatter(
    top3_df,
    x="Naam",
    y="Pearson r",
    size="abs_corr",
    color="Pearson r",
    color_continuous_scale="RdBu",
    range_color=[-1, 1],
    size_max=40,
    labels={"Naam": "Sociaal vangnet variabele", "Pearson r": "Correlatie met inkomensongelijkheid"},
    hover_data={"Pearson r": ":.2f", "abs_corr": False}
)

fig2.update_layout(
    title="Top 3 sterkste correlaties sociaal vangnet × inkomensongelijkheid",
    yaxis_title="Pearson correlatiecoëfficiënt",
    xaxis_title="",
    plot_bgcolor="white"
)

fig2.show()

# --- Argumentatieve toelichting bubble plot ---
# """
# Een veelgehoord uitgangspunt in het beleidsdebat is dat alle vormen van sociale uitgaven hetzelfde effect hebben op inkomensongelijkheid. Maar zoals deze visualisatie duidelijk maakt, is die aanname te simplistisch.
#
# In deze bubble plot staan de drie sociaal vangnet-variabelen die de sterkste statistische samenhang vertonen met inkomensongelijkheid, gemeten via de postfiscale Gini-coëfficiënt. De y-as toont de hoogte én richting van de correlatie: positief of negatief. Hoe verder een bubbel van de nul af staat, hoe sterker het verband. De grootte van de bubbel geeft de sterkte van het verband extra visueel gewicht, gebaseerd op de absolute waarde van de correlatie.
#
# Wat deze visualisatie onderscheidt, is het gebruik van betekenisvolle symbolen die direct verwijzen naar de inhoud van de variabelen. Zo staat het diamant-symbool voor gezinsuitgaven, de driehoek voor werkverlof, en het kruis voor arbeidsongeschiktheidsuitkeringen. Hierdoor is in één oogopslag duidelijk met welk beleidsdomein we te maken hebben, zonder dat de kijker technisch onderlegd hoeft te zijn.
#
# Wat zien we?
# Sommige vormen van sociale uitgaven, zoals bijvoorbeeld gezinsgerelateerde steun, laten een negatieve correlatie zien met inkomensongelijkheid. Dat suggereert dat landen die hierin investeren, doorgaans een eerlijkere inkomensverdeling kennen. Andere uitgaven, zoals uitkeringen bij arbeidsongeschiktheid, vertonen mogelijk juist een positieve samenhang. Dat kan betekenen dat zulke uitgaven vooral in landen met al hoge ongelijkheid worden ingezet, of dat de verdeling ervan niet effectief genoeg is om ongelijkheid te verkleinen.
#
# Kortom, de grafiek laat zien dat niet álle sociale uitgaven hetzelfde effect hebben op ongelijkheid. Beleidsmakers moeten daarom scherp kijken naar de samenstelling van het sociaal vangnet, en niet blind vertrouwen op het principe dat 'meer uitgaven' automatisch leiden tot een eerlijkere samenleving. Gerichte, inhoudelijk onderbouwde keuzes maken het verschil — precies wat deze visualisatie inzichtelijk maakt.
# """
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
Cell In[2], line 30
      8 var_name_map = {
      9     "sstran": "Sociale transfer",
     10     "socexp_t_pmp": "Sociale uitgaven totaal",
   (...)
     26     "othsocx_pmp": "Overige sociale uitgaven"
     27 }
     29 # Filter de correlaties op abs(waarde) > 0.3
---> 30 filtered_corr_df = corr_df_gini[(corr_df_gini["Pearson r"] > 0.3) | (corr_df_gini["Pearson r"] < -0.3)].copy()
     31 filtered_corr_df["Naam"] = filtered_corr_df.index.map(var_name_map)
     33 # Drop rijen waar de vertaling ontbreekt

NameError: name 'corr_df_gini' is not defined